/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package bean;

import entity.Contact;
import entity.Event;
import entity.Invitation;
import entity.RegisteredUser;
import entity.enumeration.EventStatus;
import entity.enumeration.InvitationStatus;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.Serializable;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import javax.annotation.PostConstruct;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ManagedProperty;
import javax.faces.bean.RequestScoped;
import javax.faces.context.FacesContext;
import mail.MailClient;
import manager.ContactManager;
import manager.EventManager;
import manager.InvitationManager;
import org.richfaces.event.UploadEvent;
import org.richfaces.model.UploadItem;
import properties.PropertyHolder;
import utils.FacesUtils;
import utils.HashGenerator;

/**
 *
 * @author Stefan Martinov
 */
@ManagedBean
@RequestScoped
public class EventsBean implements Serializable {

    protected Map<Long, Boolean> contactInvites;
    protected List<Event> userEvents;
    protected List<Event> invitedEvents;
    protected Event selectedEvent;
    protected RegisteredUser user;
    protected File image;
    protected String imageName;
    protected Boolean allContactSelectionState;
    @ManagedProperty(value = "#{registeredUserBean}")
    protected RegisteredUserBean rub;
    protected List<Contact> contacts;

    public EventsBean() {
    }

    @PostConstruct
    public void init() {
        user = rub.getRegisteredUser();
        EventManager evm = new EventManager();
        ContactManager cm = new ContactManager();
        userEvents = evm.getUserEvents(user);
        invitedEvents = evm.getUserInvitedEvents(user);
        contacts = cm.getContactsForUser(user);
        contactInvites = new HashMap<Long, Boolean>();
        initialiseContactSelection();
    }

    public List<Event> getInvitedEvents() {
        return invitedEvents;
    }

    public void setInvitedEvents(List<Event> invitedEvents) {
        this.invitedEvents = invitedEvents;
    }

    public RegisteredUser getUser() {
        return user;
    }

    public void setUser(RegisteredUser user) {
        this.user = user;
    }

    public List<Event> getUserEvents() {
        return userEvents;
    }

    public void setUserEvents(List<Event> userEvents) {
        this.userEvents = userEvents;
    }

    public Event getSelectedEvent() {
        return selectedEvent;
    }

    public void setSelectedEvent(Event selectedEvent) {
        this.selectedEvent = selectedEvent;
    }

    public void newEventAction() {
        this.selectedEvent = new Event();
        initialiseContactSelection();
    }

    public Boolean getAllContactSelectionState() {
        return allContactSelectionState;
    }

    public void setAllContactSelectionState(Boolean allContactSelectionState) {
        this.allContactSelectionState = allContactSelectionState;
    }

    public Map<Long, Boolean> getContactInvites() {
        return contactInvites;
    }

    public void setContactInvites(Map<Long, Boolean> contactInvites) {
        this.contactInvites = contactInvites;
    }

    public void listener(UploadEvent event) throws Exception {
        UploadItem item = event.getUploadItem();
        image = item.getFile();
        imageName = item.getFileName();

    }

    protected void saveImage(Event ev) {
        try {
            String settingsImagePath = PropertyHolder.getProperty("IMAGE_PATH");
            InputStream is = new FileInputStream(image.getAbsoluteFile());
            File outputFile = new File(settingsImagePath + File.separatorChar + "event" + File.separatorChar + ev.getId() + File.separatorChar + ev.getImageName());
            System.out.println("Output Image Path : " + outputFile.getAbsolutePath());

            outputFile.getParentFile().mkdirs();
            outputFile.createNewFile();

            OutputStream os = new FileOutputStream(outputFile);
            int c;
            while ((c = is.read()) != -1) {
                os.write(c);
            }
            is.close();
            os.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void save() {
        EventManager evm = new EventManager();


        System.out.println(selectedEvent.getLocation());
        selectedEvent.setStatus(EventStatus.Active);
        selectedEvent.setRegisteredUser(user);

        boolean valid = true;

        if (selectedEvent.getEndTime() != null && selectedEvent.getStartTime().after(selectedEvent.getEndTime())) {
            FacesUtils.throwFacesException("new_event_form:end_time", "End Time cannot be before Start time", FacesContext.getCurrentInstance());
            valid = false;
        }
        if (selectedEvent.getResponseTime() != null && selectedEvent.getStartTime().before(selectedEvent.getResponseTime())) {
            FacesUtils.throwFacesException("new_event_form:reply_time", "Response Time cannot be more then Start Time", FacesContext.getCurrentInstance());
            valid = false;
        }

        if (valid) {
            if (image != null) {
                selectedEvent.setImageName(imageName);
            }
            evm.create(selectedEvent);
            userEvents.add(selectedEvent);

            if (image != null) {
                saveImage(selectedEvent);
            }


            //TODO Send Contact Invites
            List<Invitation> invitationsToSend = new LinkedList<Invitation>();
            InvitationManager inm = new InvitationManager();
            ContactManager cm = new ContactManager();
            for (Long i : contactInvites.keySet()) {
                if (contactInvites.get(i)) {
                    System.out.println("Found One!");
                    Invitation inv = new Invitation();

                    inv.setContact(cm.findByID(i));
                    inv.setStatus(InvitationStatus.Pending);
                    inv.setEvent(selectedEvent);
                    inm.create(inv);
                    invitationsToSend.add(inv);
                }
            }

            SendMailsThread sendInvitations = new SendMailsThread(invitationsToSend, SendMailsThread.INVITATION);
            sendInvitations.start();

        }
    }

    public List<Contact> getContacts() {
        return contacts;
    }

    public void setContacts(List<Contact> contacts) {
        this.contacts = contacts;
    }

    public RegisteredUserBean getRub() {
        return rub;
    }

    public void setRub(RegisteredUserBean rub) {
        this.rub = rub;
    }

    public void show() {
        String url = "/EvIn/event/event_display.faces?eventId=" + selectedEvent.getId() + "&contactId=0";
        try {
            FacesContext.getCurrentInstance().getExternalContext().redirect(url);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void showInvitedEvent() {
        InvitationManager invm = new InvitationManager();
        Contact contact = invm.getContactForEvent(user, selectedEvent);
        String code = HashGenerator.generateHash(contact.getEmail());
        String url = "/EvIn/event/event_display.faces?eventId=" + selectedEvent.getId() + "&contactId=" + contact.getId() + "&code=" + code;
        try {
            FacesContext.getCurrentInstance().getExternalContext().redirect(url);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void discard() {
        try {
            Date now = Calendar.getInstance().getTime();
            EventManager evm = new EventManager();
            if (evm.checkStatusAndUpdateEvent(selectedEvent)) {
                InvitationManager inm = new InvitationManager();
                selectedEvent = evm.findByID(selectedEvent.getId());
                selectedEvent.setStatus(EventStatus.Canceled);
                evm.edit(selectedEvent);


                List<Invitation> cancelationsToSend = new LinkedList<Invitation>();
                for (int i = 0; i < userEvents.size(); i++) {
                    if (selectedEvent.getId() == userEvents.get(i).getId()) {
                        userEvents.remove(i);
                        for (Invitation inv : inm.getInvitationsForEvent(selectedEvent)) {
                            //Sending cancelation to people that accepted the invitation
                            if (inv.getStatus().equals(InvitationStatus.Attending)) {
                                cancelationsToSend.add(inv);
                            }
                        }
                        break;
                    }
                }
                SendMailsThread cancelation = new SendMailsThread(cancelationsToSend, SendMailsThread.CANCELATION);
                cancelation.start();
            }
            //TODO: Send Canceling Mails
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void initialiseContactSelection() {
        allContactSelectionState = false;
        contactInvites.clear();
        for (Contact c : contacts) {
            contactInvites.put(c.getId(), false);
        }
    }

    public void toggleSelection() {
        for (Long ci : contactInvites.keySet()) {
            contactInvites.put(ci, allContactSelectionState);
        }
    }

    public void quickNotAttending() {
    }

    public void quickAttending() {
    }
}

class SendMailsThread extends Thread {

    public static int INVITATION = 0;
    public static int CANCELATION = 1;
    private List<Invitation> invitations;
    private int type;

    public SendMailsThread(List<Invitation> invitationsToSend, int type) {
        super();
        this.invitations = invitationsToSend;
        this.type = type;
    }

    @Override
    public void run() {
        for (Invitation inv : invitations) {
            System.out.println("Sending mail to: " + inv.getContact().getEmail());
            try {
                if (type == INVITATION) {
                    MailClient.sendEventInvitation(inv);
                } else {
                    MailClient.sendEventCancelation(inv);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}
